﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Web.Mvc;

namespace MvcContrib.Shp.UI.Menu
{
    public class SecureActionMenuItem<T> : ActionMenuItem<T> where T : Controller
    {
        public SecureActionMenuItem(ViewContext viewContext, MenuSettings settings)
            : base(viewContext, settings)
        {
        }

        protected override bool IncludeItem()
        {
            if (MenuAction == null) return false;

            var callExpression = MenuAction.Body as MethodCallExpression;
            if (callExpression == null)
                throw new InvalidOperationException("Expression must be a method call");

            var attributes = GetAuthorizeAttributes(callExpression.Method);

            Disable = (Disable || !CanAddItem(attributes, ViewContext.Controller.ControllerContext));

            return !Disable;
        }

        protected virtual bool CanAddItem(IEnumerable<AuthorizeAttribute> attributes, ControllerContext context)
        {
            return attributes.All(attribute => attribute == null || attribute.Authorized(context));

            //foreach (AuthorizeAttribute attribute in attributes)
            //{
            //    if (attribute != null && !attribute.Authorized(context))
            //        return false;
            //}
            //return true;
        }

        protected virtual AuthorizeAttribute[] GetAuthorizeAttributes(MethodInfo methodInfo)
        {
            if (methodInfo == null)
            {
                throw new ArgumentNullException("methodInfo");
            }
            var typeFilters = (AuthorizeAttribute[])methodInfo.ReflectedType.GetCustomAttributes(typeof(AuthorizeAttribute), true /* inherit */);
            var methodFilters = (AuthorizeAttribute[])methodInfo.GetCustomAttributes(typeof(AuthorizeAttribute), true /* inherit */);
            var orderedFilters = typeFilters.Concat(methodFilters).OrderBy(attr => attr.Order).ToArray();
            return orderedFilters;
        }
    }
}
